﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using DataModels.Common;
using DataModels.Models;

namespace DataModels
{
    public class Services
    {
        //private static string logFilename = "iqsms";
        //private static int MAX_LOG_FILESIZE = 5242880; 

        //public static string GetSetting(string name)
        //{
        //    using (var db = new IQSMS_TestDBContext())
        //    {
        //        var r = (from s in db.SysSettings
        //                 where s.SettingName == name
        //                 select s.SettingValue).FirstOrDefault();
        //        return r;
        //    }
        //}

        //public static void SetSetting(string name, object value)
        //{
        //    if (value != null)
        //    {
        //        string sValue = value.ToString();
        //        SetSetting(name, sValue);
        //    }
        //}

        //public static void SetSetting(string name, string value)
        //{
        //    using (var db = new IQSMS_TestDBContext())
        //    {
        //        // Remove previous settings
        //        var rr = from s in db.SysSettings where s.SettingName == name select s;
        //        foreach (var r in rr) db.SysSettings.Remove(r);

        //        var setting = new SysSetting
        //        {
        //            SettingName = name,
        //            SettingValue = value
        //        };
        //        db.SysSettings.Add(setting);
        //        db.SaveChanges();
        //    }
        //}

        //public static string GetTranslationText(int errorCode)
        //{
        //    string cellnum = null;
        //    return GetTranslationText(cellnum, errorCode);
        //}

        //public static string GetTranslationText(string cellnum, int errorCode)
        //{
        //    using (var db = new IQSMS_TestDBContext())
        //    {
        //        int defaultLanguage = AutoReminderSettings.DEFAULT_SYSTEM_REPLY_LANGUAGE;
        //        if (!string.IsNullOrWhiteSpace(cellnum))
        //        {
        //            // Find user prefered language
        //            var r = (from u in db.ApprovedSMSCells
        //                     where u.CellNum == cellnum && u.LangID.HasValue
        //                     select u.LangID).ToList();
        //            if (r.Count > 0) defaultLanguage = r[0].Value;
        //        }

        //        string text = (from t in db.Translations
        //                       where t.LabelNo == errorCode
        //                       && t.LangID == defaultLanguage
        //                       select t.LText).FirstOrDefault();

        //        if (string.IsNullOrWhiteSpace(text)) text = ReportingError.DEFAULT_ERROR_MESSAGE;
        //        return text;
        //    }
        //}

        //#region Error Logging
        ///// <summary>
        ///// Logs the exception into the logfile and e-mailing it to developer
        ///// </summary>
        ///// <param name="ex"></param>
        //public static void LogError(Exception ex, DbCommand command)
        //{
        //    string error = CreateLogEntry(ex, command);
        //    WriteLog(error);

        //    if (AppConfiguration.EnableErrorLogMail)
        //    {
        //        string from = AppConfiguration.MailFrom;
        //        string to = AppConfiguration.ErrorLogEmailAddress;
        //        string subject = String.Format("{0} - Error", AppConfiguration.ApplicationName);
        //        string body = error;
        //        SendMail(from, to, subject, body);
        //    }
        //}

        ///// <summary>
        ///// Creates a detailed log entry from the exceptio object
        ///// </summary>
        ///// <param name="ex">Exception</param>
        ///// <returns></returns>
        //public static string CreateLogEntry(Exception ex, DbCommand command)
        //{
        //    string dateTime = DateTime.Now.ToLongDateString() + ", at " + DateTime.Now.ToShortTimeString();
        //    StringBuilder errorMessage = new StringBuilder();
        //    errorMessage.Append("Exception generated on " + dateTime);
        //    errorMessage.Append(Environment.NewLine);
        //    errorMessage.Append("Message: " + ex.Message);
        //    errorMessage.Append(Environment.NewLine);
        //    errorMessage.Append("Source: " + ex.Source);
        //    if (ex.InnerException != null)
        //    {
        //        errorMessage.Append(Environment.NewLine);
        //        errorMessage.Append("Inner Message: " + ex.InnerException.Message);
        //        errorMessage.Append(Environment.NewLine);
        //        errorMessage.Append("Inner Source: " + ex.InnerException.Source);

        //        try
        //        {
        //            SqlException sqlException = (SqlException)ex;
        //            WriteSQLExceptionLogEntry(sqlException, errorMessage);
        //        }
        //        catch { }
        //    }

        //    try
        //    {
        //        SqlException sqlException = (SqlException)ex;
        //        WriteSQLExceptionLogEntry(sqlException, errorMessage);
        //    }
        //    catch { }

        //    errorMessage.Append(Environment.NewLine);
        //    errorMessage.Append("Beginning Stack Trace: ");
        //    errorMessage.Append(Environment.NewLine);
        //    errorMessage.Append(ex.StackTrace);
        //    errorMessage.Append(Environment.NewLine);
        //    errorMessage.Append("Ending Stack Trace");
        //    errorMessage.Append(Environment.NewLine);
        //    errorMessage.Append(Environment.NewLine);

        //    if (command != null) WriteDbCommandLogEntry(command, errorMessage);

        //    return errorMessage.ToString();
        //}

        ///// <summary>
        ///// Write contents into the hard disk log file
        ///// </summary>
        ///// <param name="contents">Contents of the log</param>
        //public static void WriteLog(string contents)
        //{
        //    string logFileDirectory = AppConfiguration.LogFileDirectory;
        //    if (!Directory.Exists(logFileDirectory)) Directory.CreateDirectory(logFileDirectory);
        //    string filename = logFileDirectory + @"\" + logFilename + ".log";
        //    if (!File.Exists(filename)) File.Create(filename).Close();

        //    FileInfo fileInfo = new FileInfo(filename);
        //    FileStream logFile = null;
        //    if (fileInfo.Length > MAX_LOG_FILESIZE)
        //    {
        //        string date = DateTime.Now.ToLongDateString().Replace("/", "-");
        //        string time = DateTime.Now.ToLongTimeString().Replace(":", "");
        //        string oldLogFilename = logFilename + " [" + date + " " + time + "]" + ".log";
        //        File.Move(filename, oldLogFilename);
        //        logFile = new FileStream(filename, FileMode.Create);

        //    }
        //    else
        //    {
        //        logFile = new FileStream(filename, FileMode.Append);
        //    }

        //    byte[] logContents = Encoding.UTF8.GetBytes(contents);
        //    logFile.Write(logContents, 0, logContents.Length);
        //    logFile.Flush();
        //    logFile.Close();
        //}

        //public static void WriteSQLExceptionLogEntry(SqlException sqlException, StringBuilder errorMessage)
        //{
        //    errorMessage.Append(Environment.NewLine);
        //    errorMessage.Append("Sql Exception Details:");
        //    errorMessage.Append(Environment.NewLine);
        //    errorMessage.Append(Environment.NewLine);

        //    errorMessage.Append(".NET Framework Data Provider for SQL Server severity Level: ");
        //    errorMessage.Append(sqlException.Class);
        //    errorMessage.Append(Environment.NewLine);

        //    errorMessage.Append("HRESULT Error: ");
        //    errorMessage.Append(sqlException.ErrorCode);
        //    errorMessage.Append(Environment.NewLine);

        //    errorMessage.Append("Help link: ");
        //    errorMessage.Append(sqlException.HelpLink);
        //    errorMessage.Append(Environment.NewLine);

        //    errorMessage.Append("Method that throws exception: ");
        //    errorMessage.Append(sqlException.TargetSite);
        //    errorMessage.Append(Environment.NewLine);

        //    errorMessage.Append(Environment.NewLine);
        //    if (sqlException.Errors.Count > 0)
        //    {
        //        errorMessage.Append("Additional Error Information: ");
        //        errorMessage.Append(sqlException.Errors.Count);
        //        string er = (sqlException.Errors.Count == 1) ? " error" : " errors";
        //        errorMessage.Append(er);
        //        errorMessage.Append(Environment.NewLine);

        //        int count = 0;
        //        foreach (SqlError error in sqlException.Errors)
        //        {
        //            errorMessage.Append("Details of Error :");
        //            errorMessage.Append(++count);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Severity Level: ");
        //            errorMessage.Append(error.Class);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Line number within Transact-SQL command: ");
        //            errorMessage.Append(error.LineNumber);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Message: ");
        //            errorMessage.Append(error.Message);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Error Type Number: ");
        //            errorMessage.Append(error.Number);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Stored Procedure or RPC: ");
        //            errorMessage.Append(error.Procedure);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("SQL Server instance name: ");
        //            errorMessage.Append(error.Server);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Provider name: ");
        //            errorMessage.Append(error.Source);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("SQL Server numeric code: ");
        //            errorMessage.Append(error.State);
        //            errorMessage.Append(Environment.NewLine);
        //        }
        //    }
        //}

        //public static void WriteDbCommandLogEntry(DbCommand command, StringBuilder errorMessage)
        //{
        //    string state = (command.Connection.State == ConnectionState.Open) ? "Open" : "Not Open";
        //    errorMessage.Append("Connection State: ");
        //    errorMessage.Append(state);
        //    errorMessage.Append(Environment.NewLine);

        //    errorMessage.Append("Command Text: ");
        //    errorMessage.Append(command.CommandText);
        //    errorMessage.Append(Environment.NewLine);

        //    errorMessage.Append("Command Timeout: ");
        //    errorMessage.Append(command.CommandTimeout);
        //    errorMessage.Append(Environment.NewLine);

        //    string type = String.Empty;
        //    if (command.CommandType == CommandType.TableDirect) type = "Table";
        //    if (command.CommandType == CommandType.Text) type = "SQL Text Command";
        //    if (command.CommandType == CommandType.StoredProcedure) type = "Stored Procedure";
        //    errorMessage.Append("Command Type: ");
        //    errorMessage.Append(type);
        //    errorMessage.Append(Environment.NewLine);

        //    errorMessage.Append("Parameter Count: ");
        //    errorMessage.Append(command.Parameters.Count);
        //    errorMessage.Append(Environment.NewLine);

        //    if (command.Parameters.Count > 0)
        //    {
        //        int count = 0;
        //        foreach (DbParameter param in command.Parameters)
        //        {
        //            errorMessage.Append("Parameter: ");
        //            errorMessage.Append(++count);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Parameter Name: ");
        //            errorMessage.Append(param.ParameterName);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Parameter Value: ");
        //            string value = "NULL";
        //            try { value = param.Value.ToString(); }
        //            catch { }
        //            errorMessage.Append(value);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Parameter DbType: ");
        //            string dbType = "UNSPECIFIED OR OTHER TYPES";
        //            try
        //            {
        //                if (param.DbType == DbType.Boolean) dbType = "Boolean";
        //                if (param.DbType == DbType.DateTime) dbType = "DateTime";
        //                if (param.DbType == DbType.Int32) dbType = "Integer";
        //                if (param.DbType == DbType.String) dbType = "String";
        //            }
        //            catch { }
        //            errorMessage.Append(dbType);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append("Parameter Size: ");
        //            errorMessage.Append(param.Size);
        //            errorMessage.Append(Environment.NewLine);

        //            errorMessage.Append(Environment.NewLine);
        //        }
        //    }
        //}
        //#endregion

        //#region Sending E-Mail Methods
        //static string from;
        //static string to;
        //static string subject;
        //static string body;

        ///// <summary>
        ///// Sends email
        ///// </summary>
        ///// <param name="from">Source address</param>
        ///// <param name="to">Destination address</param>
        ///// <param name="subject">Subject</param>
        ///// <param name="body">Body</param>
        //public static void SendMail(string from, string to, string subject, string body)
        //{
        //    Services.from = from;
        //    Services.to = to;
        //    Services.subject = subject;
        //    Services.body = body;

        //    Thread thread = new Thread(new ThreadStart(SendMail));
        //}

        ///// <summary>
        ///// Actual sending of e-mail
        ///// </summary>
        //private static void SendMail()
        //{
        //    NetworkCredential credential = new NetworkCredential();
        //    credential.UserName = AppConfiguration.MailUsername;
        //    credential.Password = AppConfiguration.MailPassword;

        //    SmtpClient client = new SmtpClient();
        //    client.Host = AppConfiguration.MailServer;
        //    client.Port = AppConfiguration.MailServerPort;
        //    client.UseDefaultCredentials = false;
        //    client.EnableSsl = true;
        //    client.Credentials = credential;

        //    MailMessage message = new MailMessage(from, to, subject, body);
        //    try
        //    {
        //        client.Send(message);
        //    }
        //    catch (Exception ex)
        //    {
        //        string errorMessage = CreateLogEntry(ex, null);
        //        WriteLog(errorMessage);
        //    }
        //}

        ///// <summary>
        ///// Sends e-mail. Throws exception
        ///// </summary>
        ///// <param name="to">Destination e-mail address</param>
        ///// <param name="subject">E-mail subject</param>
        ///// <param name="body">E-mail body</param>
        //public static void SendMailSync(string to, string subject, string body)
        //{
        //    NetworkCredential credential = new NetworkCredential();
        //    credential.UserName = AppConfiguration.MailUsername;
        //    credential.Password = AppConfiguration.MailPassword;

        //    SmtpClient client = new SmtpClient();
        //    client.Host = AppConfiguration.MailServer;
        //    client.Port = AppConfiguration.MailServerPort;
        //    client.UseDefaultCredentials = false;
        //    client.EnableSsl = true;
        //    client.Credentials = credential;

        //    MailMessage message = new MailMessage(AppConfiguration.MailFrom, to, subject, body);
        //    message.IsBodyHtml = true;
        //    try
        //    {
        //        client.Send(message);
        //    }
        //    catch (Exception ex)
        //    {
        //        string errorMessage = CreateLogEntry(ex, null);
        //        WriteLog(errorMessage);
        //        throw ex;
        //    }
        //}
        //#endregion

        /// <summary>
        /// Returns text representing the month specified by period
        /// </summary>
        /// <param name="period">Period or month</param>
        /// <param name="shortForm">False for long form otherwise 3 digit text</param>
        /// <returns>String containing month text</returns>
        public static string GetMonthText(int period, bool shortForm = false)
        {
            string text = String.Empty;
            switch (period)
            {
                case 1:
                    text = "January";
                    break;

                case 2:
                    text = "February";
                    break;

                case 3:
                    text = "March";
                    break;

                case 4:
                    text = "April";
                    break;

                case 5:
                    text = "May";
                    break;

                case 6:
                    text = "June";
                    break;

                case 7:
                    text = "July";
                    break;

                case 8:
                    text = "August";
                    break;

                case 9:
                    text = "September";
                    break;

                case 10:
                    text = "October";
                    break;

                case 11:
                    text = "November";
                    break;

                case 12:
                    text = "December";
                    break;
            }
            if (shortForm) text = text.Substring(0, 3);
            return text;
        }

        public static bool Compare(decimal value1, string sign, decimal value2)
        {
            bool result = false;
            sign = sign.ToLower();
            switch (sign)
            {
                case "<":
                case "less than":
                    result = value1 < value2;
                    break;

                case "<=":
                case "less than or equals":
                    result = value1 <= value2;
                    break;

                case "=":
                case "equals":
                    result = value1 == value2;
                    break;

                case ">=":
                case "greater than or equals":
                    result = value1 >= value2;
                    break;

                case ">":
                case "greater than":
                    result = value1 > value2;
                    break;

                case "!=":
                case "not equals":
                    result = value1 != value2;
                    break;

                default:
                    result = false;
                    break;
            }
            return result;
        }

        #region Object Serialization
        private static object DeserializeString(string serializedObject, Type objectType)
        {
            if (string.IsNullOrWhiteSpace(serializedObject)) return null;

            // Remove any namespace attribute.
            string xmlnsPattern = "\\s+xmlns\\s*(:\\w)?\\s*=\\s*\\\"(?<url>[^\\\"]*)\\\"";
            serializedObject = Regex.Replace(serializedObject, xmlnsPattern, "");

            var deserializer = new System.Xml.Serialization.XmlSerializer(objectType);
            var reader = new System.IO.StringReader(serializedObject);
            using (var xmlReader = System.Xml.XmlReader.Create(reader))
            {
                if (deserializer.CanDeserialize(xmlReader))
                {
                    try
                    {
                        var e = deserializer.Deserialize(xmlReader);
                        return e;
                    }
                    catch
                    {
                        return null;
                    }
                }
                else return null;
            }
        }

        public static object Deserialize(object inputObject, Type targetOutputType)
        {
            if (inputObject == null) return null;
            StringBuilder sBuilder = new StringBuilder();
            using (var xmlWriter = XmlWriter.Create(sBuilder))
            {
                var serializer = new XmlSerializer(inputObject.GetType());
                serializer.Serialize(xmlWriter, inputObject);
                var serializedObject = sBuilder.ToString();
                return Services.DeserializeString(serializedObject, targetOutputType);
            }
        }
        #endregion
    }
}
